﻿using PGMHelper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace HystereticBasic
{
    /// <summary>
    /// 延性系数对象
    /// 三种延性系数集合
    /// </summary>
    public class DuctilityObj
    {
        #region Variables

        /// <summary>
        /// 延性系数对象列表
        /// </summary>
        private List<DuctilityBasic> ductList { set; get; }

        /// <summary>
        /// 原始骨架
        /// </summary>
        private MontForceDispObj originSkeletonObj { set; get; }

        /// <summary>
        /// 骨架曲线
        /// </summary>
        private MontForceDispObj SkeletonObj { set; get; }

        /// <summary>
        /// 极限承载力点
        /// </summary>
        private ForceDispBasicPair UltimatePoint { set; get; }

        /// <summary>
        /// 极限承载力系数
        /// </summary>
        private float UltimateStrengthFactor { set; get; }

        /// <summary>
        /// 对象名称
        /// </summary>
        public string Name { set; get; }

        #endregion

        #region properties

        /// <summary>
        /// 是否合法
        /// </summary>
        public bool isLegal
        {
            get
            {
                return this.ductList.Count != 0;
            }
        }

        /// <summary>
        /// 屈服力
        /// </summary>
        public float AVGYieldForce
        {
            get
            {
                return (from basic in this.ductList
                        select basic.YieldForce).ToList().Average();
            }
        }

        /// <summary>
        /// 屈服位移
        /// </summary>
        public float AVGYieldDisp
        {
            get
            {
                return (from basic in this.ductList
                        select basic.YieldDisp).ToList().Average();
            }
        }

        /// <summary>
        /// 屈服延性系数
        /// </summary>
        public float AVGYieldDucFactor
        {
            get
            {
                return (from basic in this.ductList
                        select basic.YieldDucFactor).ToList().Average();
            }
        }

        /// <summary>
        /// 延性系数相关
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public float this[DataType dataType]
        {
            get
            {
                switch (dataType)
                {
                    //峰值点
                    case DataType.DuctilityPeakForce:
                        return this.SkeletonObj.ForceMaxPoint.Force;
                    case DataType.DuctilityPeakDisp:
                        return this.SkeletonObj.ForceMaxPoint.Disp;

                    //极限变形点
                    case DataType.DuctilityUltimateForce:
                        return this.UltimatePoint.Force;
                    case DataType.DuctilityUltimateDisp:
                        return this.UltimatePoint.Disp;

                    //屈服点
                    case DataType.DuctilityYieldForce:
                        return this.AVGYieldForce;
                    case DataType.DuctilityYieldDisp:
                        return this.AVGYieldDisp;
                    case DataType.DuctilityFactor:
                        return this.AVGYieldDucFactor;

                    default: return 0;
                }

            }
        }

        /// <summary>
        /// 某性能下的延性系数
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="dMethod"></param>
        /// <returns></returns>
        public float this[DataType dataType, DuctilityMethod dMethod]
        {
            get
            {
                //是否与方法相关
                switch(dataType)
                {
                    case DataType.DuctilityYieldForce:
                    case DataType.DuctilityYieldDisp:
                    case DataType.DuctilityFactor:
                        {
                            //平均值
                            if (dMethod != DuctilityMethod.AVG)
                            {
                                //初始化
                                DuctilityBasic dBasic;
                                //获得对象
                                if (!this.GetDuctilityBasic(dMethod, out dBasic))
                                    return 0;
                                //延性对象
                                else return dBasic[dataType];
                            }
                            else return this[dataType];
                        }
                    default: return this[dataType];
                }
            }
        }

        #endregion

        /// <summary>
        /// 设定峰值及极限承载力
        /// </summary>
        /// <param name="textBoxList"></param>
        public void PeakUltimateTextbox(List<TextBox> textBoxList)
        {
            //数目是否合适
            if (textBoxList.Count < 4) return;
            //获得峰值点
            var peakPt = this.SkeletonObj.ForceMaxPoint;
            //设定文本
            textBoxList[0].Text = peakPt.Disp.ToString("f2");
            textBoxList[1].Text = peakPt.Force.ToString("f1");
            textBoxList[2].Text = this.UltimatePoint.Disp.ToString("f2");
            textBoxList[3].Text = this.UltimatePoint.Force.ToString("f1");
        }

        /// <summary>
        /// 更新文本框
        /// </summary>
        /// <param name="textBoxList"></param>
        public void DuctilityToTextbox(List<TextBox> textBoxList, DuctilityMethod dMethod)
        {
            //平均值
            if (dMethod != DuctilityMethod.AVG)
            {
                //初始化
                DuctilityBasic dBasic;
                //获得对象
                if (!this.GetDuctilityBasic(dMethod, out dBasic)) return;
                //刷新文本框
                this.DuctilityToTextbox(textBoxList, dBasic.YieldForce, dBasic.YieldDisp,
                    dBasic.YieldDucFactor);
            }
            else this.DuctilityToTextbox(textBoxList, this.AVGYieldForce, this.AVGYieldDisp, this.AVGYieldDucFactor);
        }

        /// <summary>
        /// 更新文本框
        /// </summary>
        /// <param name="textBoxList"></param>
        private void DuctilityToTextbox(List<TextBox> textBoxList,
            float force, float disp, float ducFactor)
        {
            //确认数量
            if (textBoxList.Count < 3) return;
            //获得数据
            textBoxList[0].Text = disp.ToString("f2");
            textBoxList[1].Text = force.ToString("f1");
            textBoxList[2].Text = ducFactor.ToString("f2");
        }

        /// <summary>
        /// 获得延性系数对象
        /// </summary>
        /// <param name="dMethod"></param>
        /// <param name="dBasic"></param>
        /// <returns></returns>
        public bool GetDuctilityBasic(DuctilityMethod dMethod, out DuctilityBasic dBasic)
        {
            //初始化
            dBasic = new DuctilityBasic();
            //遍历
            foreach (var obj in this.ductList)
            {
                if (obj.GetMethod() == dMethod)
                {
                    dBasic = obj;
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 绘图
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="dMethod"></param>
        public void ToChart(Chart chart, DuctilityMethod dMethod)
        {
            //初始化
            DuctilityBasic dBasic;
            //获得对象
            if (!this.GetDuctilityBasic(dMethod, out dBasic))
            {
                MessageBoxExtern.Warnning(string.Format("构件{0}不存在{1}延性对象",
                    this.Name, dMethod.ToString()));
                return;
            }
            //设定图像图名
            chart.SetTitle(TiltleType.Header, this.Name);
            //绘图
            dBasic.ToChart(chart);
        }

        #region Construction

        /// <summary>
        /// 设定极限位移点
        /// </summary>
        private void SetUltimatePoint()
        {
            //最后的数据点
            this.UltimatePoint = this.SkeletonObj.Last();
            //限定数据点数目
            if (this.SkeletonObj.Count < 2) return;
            //力限值
            var forceLimit = Math.Abs(this.SkeletonObj.ForceMaxPoint.Force * this.UltimateStrengthFactor);
            //获得新的数据点
            ForceDispBasicPair interPt;
            //插值
            if (this.SkeletonObj.GetPtByForce(forceLimit, false, out interPt))
            {
                //存在插值点
                this.UltimatePoint = interPt;
                return;
            }
            //获得点
            var ptI = this.SkeletonObj[this.SkeletonObj.Count - 2];
            var ptJ = this.SkeletonObj.Last();
            //非负刚度
            if (ptI.GetStiffness(ptJ) >= 0) return;
            //力需要大于目标
            if (Math.Abs(ptJ.Force) < forceLimit) return;
            //插值获得数据点
            if (!ptI.GetInterpolationPt(ptJ, forceLimit, out interPt)) return;
            //防止目标位移过大
            if (Math.Abs(interPt.Disp) > GlobalParam.VirtualUnloadPtDispFactor * Math.Abs(ptJ.Disp))
                return;
            //添加目标点
            this.UltimatePoint = interPt;
            this.SkeletonObj.Add(this.UltimatePoint);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void SetDuctilityFactor(float ultimateStrengthFactor, float parkFactor)
        {
            //复制数据
            this.SkeletonObj = new MontForceDispObj(this.originSkeletonObj);
            this.UltimateStrengthFactor = ultimateStrengthFactor;
            //判断是否正向加载
            if (Math.Abs(this.SkeletonObj.ForceMinPoint.Force) >
                Math.Abs(this.SkeletonObj.ForceMaxPoint.Force))
            {
                this.SkeletonObj.DispAmplitude(-1);
                this.SkeletonObj.ForceAmplitude(-1);
            }
            //设定极限变形点
            this.SetUltimatePoint();
            //初始化
            this.ductList = new List<DuctilityBasic>();
            //三种方法
            var generalObj = new DuctilityGeneral(this.SkeletonObj, this.UltimatePoint);
            var energyObj = new DuctilityEnergy(this.SkeletonObj, this.UltimatePoint);
            var park = new DuctilityPark(this.SkeletonObj, this.UltimatePoint, parkFactor);
            //构造屈服点
            if (generalObj.SetYieldPt()) this.ductList.Add(generalObj);
            if (energyObj.SetYieldPt()) this.ductList.Add(energyObj);
            if (park.SetYieldPt()) this.ductList.Add(park);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private DuctilityObj()
        {
            this.ductList = new List<DuctilityBasic>();
        }

        /// <summary>
        /// 延性系数计算
        /// </summary>
        /// <param name="skeletonObj"></param>
        /// <param name="ultimateStrengthFactor"></param>
        /// <param name="parkFactor"></param>
        public DuctilityObj(MontForceDispObj skeletonObj, string name,
            float ultimateStrengthFactor, float parkFactor):this()
        {
            //获得名称
            this.Name = name;
            this.originSkeletonObj = skeletonObj;
            //最大力小于0
            if (this.originSkeletonObj.ForceMaxPoint.Force <= 0) return;
            //初始化
            this.SetDuctilityFactor(ultimateStrengthFactor, parkFactor);
        }

        /// <summary>
        /// 延性系数计算
        /// </summary>
        /// <param name="data"></param>
        /// <param name="ultimateStrengthFactor"></param>
        /// <param name="parkFactor"></param>
        public DuctilityObj(BasicData data, bool isPos,
            float ultimateStrengthFactor,  float parkFactor) : this()
        {
            //获得名称
            this.Name = data.FileName;
            this.originSkeletonObj = data.GetSkeletonObj(isPos);
            //骨架数据点存在
            if (this.originSkeletonObj.Count < 3) return;
            //初始化
            this.SetDuctilityFactor(ultimateStrengthFactor, parkFactor);
        }

        #endregion
    }
}
